import { parseTime } from "./ruoyi";

/**
 * 表格时间格式化
 */
export function formatDate(cellValue) {
  if (cellValue == null || cellValue == "") return "";
  var date = new Date(cellValue);
  var year = date.getFullYear();
  var month =
    date.getMonth() + 1 < 10
      ? "0" + (date.getMonth() + 1)
      : date.getMonth() + 1;
  var day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
  var hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
  var minutes =
    date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
  var seconds =
    date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
  return (
    year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds
  );
}

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (("" + time).length === 10) {
    time = parseInt(time) * 1000;
  } else {
    time = +time;
  }
  const d = new Date(time);
  const now = Date.now();

  const diff = (now - d) / 1000;

  if (diff < 30) {
    return "刚刚";
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + "分钟前";
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + "小时前";
  } else if (diff < 3600 * 24 * 2) {
    return "1天前";
  }
  if (option) {
    return parseTime(time, option);
  } else {
    return (
      d.getMonth() +
      1 +
      "月" +
      d.getDate() +
      "日" +
      d.getHours() +
      "时" +
      d.getMinutes() +
      "分"
    );
  }
}

export const guid = () => {
  return "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, function (c) {
    let r = (Math.random() * 16) | 0,
      v = c === "x" ? r : (r & 0x3) | 0x8;
    return v.toString(16);
  });
};

/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url) {
  url = url == null ? window.location.href : url;
  const search = url.substring(url.lastIndexOf("?") + 1);
  const obj = {};
  const reg = new RegExp("([^?&=]+)=([^?&=]*)", "gi");
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1);
    let val = decodeURIComponent($2);
    val = String(val);
    obj[name] = val;
    return rs;
  });
  return obj;
}

/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
  // returns the byte length of an utf8 string
  let s = str.length;
  for (var i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) {
      s++;
    } else if (code > 0x7ff && code <= 0xffff) s += 2;
    if (code >= 0xdc00 && code <= 0xdfff) i--;
  }
  return s;
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
  const newArray = [];
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i]);
    }
  }
  return newArray;
}

/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json) {
  if (!json) return "";
  return cleanArray(
    Object.keys(json).map((key) => {
      if (json[key] === undefined) return "";
      return encodeURIComponent(key) + "=" + encodeURIComponent(json[key]);
    })
  ).join("&");
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = decodeURIComponent(url.split("?")[1]).replace(/\\+/g, " ");
  if (!search) {
    return {};
  }
  const obj = {};
  const searchArr = search.split("&");
  searchArr.forEach((v) => {
    const index = v.indexOf("=");
    if (index !== -1) {
      const name = v.substring(0, index);
      const val = v.substring(index + 1, v.length);
      obj[name] = val;
    }
  });
  return obj;
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement("div");
  div.innerHTML = val;
  return div.textContent || div.innerText;
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return;
  }
  let classString = element.className;
  const nameIndex = classString.indexOf(className);
  if (nameIndex === -1) {
    classString += "" + className;
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length);
  }
  element.className = classString;
}

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type) {
  if (type === "start") {
    return new Date().getTime() - 3600 * 1000 * 24 * 90;
  } else {
    return new Date(new Date().toDateString());
  }
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result;

  const later = function () {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp;

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null;
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  };

  return function (...args) {
    context = this;
    timestamp = +new Date();
    const callNow = immediate && !timeout;
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args);
      context = args = null;
    }

    return result;
  };
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== "object") {
    throw new Error("error arguments", "deepClone");
  }
  const targetObj = source.constructor === Array ? [] : {};
  Object.keys(source).forEach((keys) => {
    if (source[keys] && typeof source[keys] === "object") {
      targetObj[keys] = deepClone(source[keys]);
    } else {
      targetObj[keys] = source[keys];
    }
  });
  return targetObj;
}

/**
 * 对象深拷贝
 */
export const _deepClone = (data) => {
  var type = getObjType(data);
  var obj;
  if (type === "array") {
    obj = [];
  } else if (type === "object") {
    obj = {};
  } else {
    //不再具有下一层次
    return data;
  }
  if (type === "array") {
    for (var i = 0, len = data.length; i < len; i++) {
      obj.push(_deepClone(data[i]));
    }
  } else if (type === "object") {
    for (var key in data) {
      obj[key] = _deepClone(data[key]);
    }
  }
  return obj;
};

export const getObjType = (obj) => {
  var toString = Object.prototype.toString;
  var map = {
    "[object Boolean]": "boolean",
    "[object Number]": "number",
    "[object String]": "string",
    "[object Function]": "function",
    "[object Array]": "array",
    "[object Date]": "date",
    "[object RegExp]": "regExp",
    "[object Undefined]": "undefined",
    "[object Null]": "null",
    "[object Object]": "object",
  };
  if (obj instanceof Element) {
    return "element";
  }
  return map[toString.call(obj)];
};

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr));
}

/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = +new Date() + "";
  const randomNum = parseInt((1 + Math.random()) * 65535) + "";
  return (+(randomNum + timestamp)).toString(32);
}

/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele, cls) {
  return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
}

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += " " + cls;
}

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
    ele.className = ele.className.replace(reg, " ");
  }
}

export function makeMap(str, expectsLowerCase) {
  const map = Object.create(null);
  const list = str.split(",");
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true;
  }
  return expectsLowerCase ? (val) => map[val.toLowerCase()] : (val) => map[val];
}

export const exportDefault = "export default ";

export const beautifierConf = {
  html: {
    indent_size: "2",
    indent_char: " ",
    max_preserve_newlines: "-1",
    preserve_newlines: false,
    keep_array_indentation: false,
    break_chained_methods: false,
    indent_scripts: "separate",
    brace_style: "end-expand",
    space_before_conditional: true,
    unescape_strings: false,
    jslint_happy: false,
    end_with_newline: true,
    wrap_line_length: "110",
    indent_inner_html: true,
    comma_first: false,
    e4x: true,
    indent_empty_lines: true,
  },
  js: {
    indent_size: "2",
    indent_char: " ",
    max_preserve_newlines: "-1",
    preserve_newlines: false,
    keep_array_indentation: false,
    break_chained_methods: false,
    indent_scripts: "normal",
    brace_style: "end-expand",
    space_before_conditional: true,
    unescape_strings: false,
    jslint_happy: true,
    end_with_newline: true,
    wrap_line_length: "110",
    indent_inner_html: true,
    comma_first: false,
    e4x: true,
    indent_empty_lines: true,
  },
};

// 首字母大小
export function titleCase(str) {
  return str.replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
}

// 下划转驼峰
export function camelCase(str) {
  return str.replace(/-[a-z]/g, (str1) => str1.substr(-1).toUpperCase());
}

export function isNumberStr(str) {
  return /^[+-]?(0|([1-9]\\d*))(\\.\\d+)?$/g.test(str);
}

/**
 * 两个对象合并 以第一个对象的Key为准
 * create by 刘杨
 * @param obj1 对象
 * @param obj2 对象
 * @returns obj1
 */
export function mergeObject(obj1 = {}, obj2 = {}) {
  // 获取第一个对象的keys
  let keys = Object.keys(obj1);
  // 查找当前对象每个属性是否有引用类型
  let index = keys.findIndex(
    (key) => obj1[key].toString() === "[object Object]"
  );

  if (index === -1) {
    // 无引用类型 直接合并
    obj1 = Object.assign(obj1, obj2);
  } else {
    // 有引用类型 遍历
    keys.forEach((key) => {
      // 都是对象类型 调用自身继续合并
      if (
        obj1[key] &&
        obj2[key] &&
        obj1[key].toString() === "[object Object]" &&
        obj1[key].toString() === obj2[key].toString()
      ) {
        let child = mergeObject(obj1[key], obj2[key]);
        obj1[key] = Object.assign(obj1[key], child);
      } else {
        // 不是对象类型 取有值的合并
        obj1[key] = obj2[key] === undefined ? obj1[key] : obj2[key];
      }
    });
  }
  return obj1;
}

/**
 * 数据库字段类型 转换
 * @param type 原始数据库字段类型
 * @returns fieldType 业务规定类型 日期类型: date 字符类型: string 数字类型: number
 */
export function transformFieldType(type = "string") {
  type = type.toLowerCase();
  // result: date number string
  // MySQL 和 Oracle 所有 [ 字符 ] 类型
  const stringType = [
    "char",
    "varchar",
    "tinyblob",
    "tinytext",
    "blob",
    "text",
    "mediumblob",
    "mediumtext",
    "longblob",
    "longtext",
    "enum",
    "set",
    "varchar2",
    "nchar",
    "nvarchar2",
    "long",
    "raw",
    "long raw",
    "clob",
    "nclob",
    "bfile",
    "rowid",
    "nrowid",
    "nvarchar",
    "string",
  ];
  // MySQL 和 Oracle 所有 [ 数字 ] 类型
  const numberType = [
    "tinyint",
    "smallint",
    "mediumint",
    "int",
    "integer",
    "bigdecimal",
    "bigint",
    "float",
    "double",
    "decimal",
    "number",
    "real",
    "bit",
    "numberic",
    "binary_float",
    "binary_double",
  ];
  // MySQL 和 Oracle 所有 [ 日期 ] 类型
  const dateType = ["date", "time", "year", "datetime", "timestamp"];

  if (numberType.includes(type)) return "number";
  if (dateType.includes(type)) return "date";
  return "string";
}

/** 获取鼠标在某个div中的上下左右位置
 * @param pageX
 * @param pageY
 * @param x div顶部位置
 * @param y div左侧位置
 * @param xWidth  div底部位置
 * @param yHeight div右侧位置
 */
export function getPosition(pageX, pageY, x, y, xWidth, yHeight) {
  let center = { x: (xWidth - x) / 2 + x, y: (yHeight - y) / 2 + y },
    x1 = { x: x, y: y },
    x2 = { x: xWidth, y: y },
    x3 = { x: x, y: yHeight },
    x4 = { x: xWidth, y: yHeight },
    position;

  if (isRule(pageX, pageY, center, x1, x2) === "top") {
    position = "top";
  } else if (isRule(pageX, pageY, center, x1, x3) === "left") {
    position = "left";
  } else if (isRule(pageX, pageY, center, x2, x4) === "right") {
    position = "right";
  } else if (isRule(pageX, pageY, center, x3, x4) === "bottom") {
    position = "bottom";
  }
  return position;
}

/**
 * 计算鼠标和三个点之间距离
 * @param pageX
 * @param pageY
 * @param center
 * @param x1
 * @param x2
 * @param type
 */
export function isRule(pageX, pageY, center, x1, x2, type) {
  let x = pageX,
    y = pageY,
    r1 =
      y - center.y - ((x1.y - center.y) / (x1.x - center.x)) * (x - center.x),
    r2 = y - x1.y - ((x2.y - x1.y) / (x2.x - x1.x)) * (x - x1.x),
    r3 = y - x2.y - ((center.y - x2.y) / (center.x - x2.x)) * (x - x2.x);
  if (r1 > 0 && r2 < 0 && r3 > 0) {
    return "bottom";
  } else if (r1 < 0 && r2 > 0 && r3 < 0) {
    return "top";
  } else if (r1 > 0 && r2 < 0 && r3 < 0) {
    return "left";
  } else if (r1 > 0 && r2 > 0 && r3 < 0) {
    return "right";
  }
}

/**
 *
 * @param tree 树形数据
 * @param childrenKey 子集key
 */
export function deleteSubChildren(tree, childrenKey = "children") {
  const handleChildData = (arr) => {
    return arr.reduce((r, c) => {
      let child = { ...c };
      child[childrenKey] = child[childrenKey].length
        ? handleChildData(child[childrenKey])
        : null;
      r.push(child);
      return r;
    }, []);
  };

  return handleChildData(tree);
}

const Utils = {
  //YYMMDD hhmmss 转 YY-MM-DD hh:mm:ss
  formatTime(str) {
    return str.replace(
      /^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})$/,
      "$1-$2-$3 $4:$5:$6"
    );
  },
  parseTime(time, cFormat) {
    if (arguments.length === 0 || !time) {
      return null;
    }
    const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}";
    let date;
    if (typeof time === "object") {
      date = time;
    } else {
      if (typeof time === "string") {
        if (/^[0-9]+$/.test(time)) {
          // support "1548221490638"
          time = parseInt(time);
        } else {
          // support safari
          // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
          time = time.replace(new RegExp(/-/gm), "/");
        }
      }

      if (typeof time === "number" && time.toString().length === 10) {
        time = time * 1000;
      }
      date = new Date(time);
    }
    const formatObj = {
      y: date.getFullYear(),
      m: date.getMonth() + 1,
      d: date.getDate(),
      h: date.getHours(),
      i: date.getMinutes(),
      s: date.getSeconds(),
      a: date.getDay(),
    };
    const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
      const value = formatObj[key];
      // Note: getDay() returns 0 on Sunday
      if (key === "a") {
        return ["日", "一", "二", "三", "四", "五", "六"][value];
      }
      return value.toString().padStart(2, "0");
    });
    return time_str;
  },
  //2019-04-24T02:30:00.000+0000
  resolvingDate(date) {
    //date是传入的时间
    let d = new Date(date);

    let month =
      d.getMonth() + 1 < 10 ? "0" + (d.getMonth() + 1) : d.getMonth() + 1;
    let day = d.getDate() < 10 ? "0" + d.getDate() : d.getDate();
    let hours = d.getHours() < 10 ? "0" + d.getHours() : d.getHours();
    let min = d.getMinutes() < 10 ? "0" + d.getMinutes() : d.getMinutes();
    let sec = d.getSeconds() < 10 ? "0" + d.getSeconds() : d.getSeconds();

    let times =
      d.getFullYear() +
      "-" +
      month +
      "-" +
      day +
      " " +
      hours +
      ":" +
      min +
      ":" +
      sec;

    return times;
  },
  getNowTime() {
    let dateTime;
    let yy = new Date().getFullYear();
    let mm = new Date().getMonth() + 1;
    let dd = new Date().getDate();
    let hh = new Date().getHours();
    let mf =
      new Date().getMinutes() < 10
        ? "0" + new Date().getMinutes()
        : new Date().getMinutes();
    let ss =
      new Date().getSeconds() < 10
        ? "0" + new Date().getSeconds()
        : new Date().getSeconds();
    dateTime = yy + "-" + mm + "-" + dd + " " + hh + ":" + mf + ":" + ss;
    console.log(dateTime);
    return dateTime;
  },
  // 手机号加密
  phoneEncryption(str) {
    return str.substr(0, 3) + "****" + str.substr(7);
  },
  identityEncryption(str) {
    return str.substr(0, 4) + "**********" + str.substr(14);
  },
  // 邮箱加密
  emailEncryption(email) {
    let index = email.indexOf("@");
    if (index > 0) {
      if (index > 4) {
        return email.substr(0, 4) + "****" + email.substr(index);
      } else {
        return "****" + email.substr(index);
      }
    }
    return email;
  },
};
export default Utils;
